#include "IStream.h"

#include <sstream>

#include "File.h"
#include "BlockManager.h"

namespace streamdb {

class StreamFileImp : public IStream{
public:
    StreamFileImp(const std::string & name) 
    : name(name)
    , isOpened(false)
    , current(0)
    , file(name)
    {
    }

    ~StreamFileImp() override{
    }
    const std::string & getName() const override{ 
        return name;
    }

    Status open() override{
        if(isOpened == false){
            auto s = file.openRW();
            if(s.isOk()){
                s = file.getSize(current);
                if(s.isOk()){
                    isOpened = true;
                    return s;
                }
            }
            return s;
        }
        return Status::OK();
    }
    Status close() override{
        if(isOpened){
            auto s = file.close();
            if(s.isOk()){
                current = 0;
                isOpened = false;
            }
            return s;
        }
        return Status::OK();
    }

    Status append(const rocksdb::Slice & msg) override{
            //simpe impl
            uint64_t sz = msg.size();
            auto s = file.write(msg.data(), sz);
            assert(sz == msg.size());
            current += sz;
            return s;
    }
    Status flush() override{
        if(isOpened){
            return file.flush();
        }
        return Status::OK();
    }
private:
    std::string name;
    bool isOpened;
    uint64_t current;
    streamdb::File file;
};




class StreamBlockImp : public IStream {
public:
    StreamBlockImp(const std::string & name) 
    : name(name)
    , isOpened(false)
    , current(0)
    , blockManager(new BlockManager)
    {
    }

    ~StreamBlockImp() override{
        this->close();

        if(blockManager != nullptr){
            delete blockManager;
            blockManager = nullptr;
        }
    }
    const std::string & getName() const override{ 
        return name;
    }

    Status open() override{
        if(isOpened == false){
            auto s = blockManager->regStream(name);
            if(s.isOk()){
                current = 0;
                isOpened = true;
            }
            return s;
        }
        return Status::OK();
    }

    Status close() override{
        if(isOpened){
            isOpened = false;
            current = 0;
            return blockManager->unregStream(name);
        }
        return Status::OK();
    }


    Status append(const rocksdb::Slice &msg) override{
        auto s = blockManager->append(name, msg);
        if(s.isOk()){
            current += msg.size();
        }
        return s;
    }

    Status flush() override{
        if(isOpened){
            return blockManager->flush();//TODO: check point
        }
        return Status::OK();
    }

private:
    std::string name;
    bool isOpened;
    uint64_t current;
    BlockManager * blockManager;
};

std::shared_ptr<IStream> makeStream(const std::string name){
    //return std::make_shared<StreamFileImp>(name);
    return std::make_shared<StreamBlockImp>(name);
}

}//namespace streamdb
